#include "win_netw.h"
#include <stdio.h>

static bool winsockInit = false;

TNetLink *net_startUDP(int port)
{
	if (!winsockInit)
	{
		WSADATA wd;

		if (WSAStartup(MAKEWORD(2,2), &wd))
		{
			fprintf(stderr, "Could not open Windows connection.\n");
			return NULL;
		}

		winsockInit = true;
	}

	TNetLink *lnk = new TNetLink;
	lnk->port = port;

	// Open a datagram socket
	lnk->socket = socket(AF_INET, SOCK_DGRAM, 0);
	if (lnk->socket == INVALID_SOCKET)
	{
		fprintf(stderr, "Could not create socket.\n");
		net_stopUDP(lnk);
		return NULL;
	}

	// Clear out server struct
	SOCKADDR_IN server;
	ZeroMemory(&server, sizeof(server));

	// Set family and port 
	server.sin_family = AF_INET;
	server.sin_port = htons(lnk->port);

	// Get host name of this computer
	struct hostent *hp;
	char host_name[256];	
	gethostname(host_name, sizeof(host_name));
	hp = gethostbyname(host_name);

	// Check for NULL pointer
	if (hp == NULL)
	{
		fprintf(stderr, "Could not get host name.\n");
		net_stopUDP(lnk);
		return NULL;
	}
	
	// Assign the address
	server.sin_addr.S_un.S_un_b.s_b1 = hp->h_addr_list[0][0];
	server.sin_addr.S_un.S_un_b.s_b2 = hp->h_addr_list[0][1];
	server.sin_addr.S_un.S_un_b.s_b3 = hp->h_addr_list[0][2];
	server.sin_addr.S_un.S_un_b.s_b4 = hp->h_addr_list[0][3];

	lnk->address = server.sin_addr;

	// Bind address to socket
	if (bind(lnk->socket, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) == -1)
	{
		fprintf(stderr, "Could not bind name to socket.\n");
		net_stopUDP(lnk);
		return NULL;
	}

	int bcast = 1;
	if (setsockopt(lnk->socket, SOL_SOCKET, SO_BROADCAST, (char*)&bcast, sizeof(bcast)))
	{
		fprintf(stderr, "Could not enable broadcast mode.\n");
		net_stopUDP(lnk);
		return NULL;
	}
	return lnk;
}

bool net_stopUDP(TNetLink *lnk)
{
	if (lnk->socket != INVALID_SOCKET)
	{
		closesocket(lnk->socket);
		lnk->socket = INVALID_SOCKET;
	}
	return true;
}

bool net_sendUDP(TNetLink *lnk, TNetAddr *addr, void *buf, int len)
{
	SOCKADDR_IN saddr;

	saddr.sin_family = AF_INET;
	saddr.sin_port = htons(lnk->port);
	if (addr)
		saddr.sin_addr = *addr;
	else
		saddr.sin_addr.S_un.S_addr = INADDR_BROADCAST;

	return sendto(lnk->socket, (char*)buf, len, 0, (sockaddr*)&saddr, sizeof(saddr))>0;
}

int net_recvUDP(TNetLink *lnk, TNetAddr *addr, void *buf, int len)
{
	SOCKADDR_IN saddr;
	ZeroMemory(&saddr, sizeof(saddr));
	int slen = sizeof(saddr);

	int n = recvfrom(lnk->socket, (char*)buf, len, 0, (sockaddr*)&saddr, &slen);

	if (addr != NULL)
		*addr = saddr.sin_addr;

	return n;
}

void net_getAddrStr(TNetAddr *addr, char *buf)
{
	sprintf(buf,"%d.%d.%d.%d", addr->S_un.S_un_b.s_b1, addr->S_un.S_un_b.s_b2, addr->S_un.S_un_b.s_b3, addr->S_un.S_un_b.s_b4);
}

void net_getAddrFromStr(TNetAddr *addr, char *buf)
{
	addr->S_un.S_addr = inet_addr(buf);
}

